#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""更新下载器模块
负责安全下载和验证更新包文件"""

import os
import shutil
import hashlib
import tempfile
import threading
import urllib.request
import urllib.error
import time
from utils import Logger, FileUtils
from utils.auto_update.config_manager import UpdateConfigManager

class UpdateDownloader:
    """更新下载器
    负责安全下载和验证更新包文件"""
    
    def __init__(self):
        """初始化更新下载器"""
        self.config_manager = UpdateConfigManager()
        self.download_dir = self._get_download_dir()
        self.is_downloading = False
        self.current_download_progress = 0
        self._download_lock = threading.Lock()
        self._stop_event = threading.Event()
        Logger.log_info(f"更新下载器初始化完成，下载目录: {self.download_dir}")
    
    def _get_download_dir(self):
        """获取下载目录
        
        Returns:
            str: 下载目录路径
        """
        # 从配置中获取下载目录
        config_dir = self.config_manager.get_config("download_dir")
        
        if config_dir and os.path.exists(config_dir):
            return config_dir
        
        # 如果配置中没有或目录不存在，使用系统临时目录
        temp_dir = tempfile.gettempdir()
        app_temp_dir = os.path.join(temp_dir, "ProfessionalStockAnalysis")
        
        # 确保目录存在
        if not os.path.exists(app_temp_dir):
            try:
                os.makedirs(app_temp_dir)
                Logger.log_info(f"创建临时下载目录: {app_temp_dir}")
            except Exception as e:
                Logger.log_error(f"创建临时下载目录失败: {str(e)}")
                # 如果创建失败，回退到系统临时目录
                app_temp_dir = temp_dir
        
        return app_temp_dir
    
    def download_update(self, download_url, callback=None):
        """下载更新包
        
        Args:
            download_url: 更新包的下载URL
            callback: 下载进度回调函数，接受参数(progress, total_size, downloaded_size)
            
        Returns:
            str: 下载的文件路径，如果下载失败则返回None
        """
        # 尝试获取线程锁，确保同一时间只有一个下载操作在执行
        if not self._download_lock.acquire(blocking=False):
            Logger.log_info("下载任务已经在进行中，跳过本次请求")
            return None
        
        self._stop_event.clear()
        self.is_downloading = True
        self.current_download_progress = 0
        
        try:
            Logger.log_info(f"开始下载更新包: {download_url}")
            
            # 获取文件名
            file_name = os.path.basename(download_url.split('?')[0])  # 去掉URL参数
            if not file_name:
                file_name = f"update_{int(time.time())}.zip"
            
            # 构建下载路径
            download_path = os.path.join(self.download_dir, file_name)
            
            # 设置下载超时
            timeout = self.config_manager.get_config("download_timeout", 300)
            
            # 模拟下载过程
            # 在实际应用中，这里应该使用urllib.request.urlretrieve或类似方法下载文件
            success = self._simulate_download(download_url, download_path, timeout, callback)
            
            if success:
                Logger.log_info(f"更新包下载完成: {download_path}")
                
                # 验证下载的文件
                if self._verify_downloaded_file(download_path):
                    Logger.log_info("更新包验证成功")
                    return download_path
                else:
                    Logger.log_error("更新包验证失败")
                    # 删除验证失败的文件
                    if os.path.exists(download_path):
                        os.remove(download_path)
                    return None
            else:
                Logger.log_error("更新包下载失败")
                return None
        except Exception as e:
            Logger.log_error(f"下载更新包时发生错误: {str(e)}")
            return None
        finally:
            self.is_downloading = False
            self._download_lock.release()
    
    def _simulate_download(self, url, save_path, timeout, callback):
        """模拟下载过程
        
        Args:
            url: 下载URL
            save_path: 保存路径
            timeout: 超时时间(秒)
            callback: 进度回调函数
            
        Returns:
            bool: 是否下载成功
        """
        # 模拟文件大小(5MB)
        total_size = 5 * 1024 * 1024
        downloaded_size = 0
        chunk_size = 1024 * 100  # 100KB chunks
        
        # 创建一个空文件用于模拟下载
        with open(save_path, 'wb') as f:
            while downloaded_size < total_size and not self._stop_event.is_set():
                # 模拟下载数据
                chunk = b'0' * min(chunk_size, total_size - downloaded_size)
                f.write(chunk)
                downloaded_size += len(chunk)
                
                # 更新进度
                progress = int(downloaded_size / total_size * 100)
                self.current_download_progress = progress
                
                # 调用回调函数
                if callback:
                    try:
                        callback(progress, total_size, downloaded_size)
                    except Exception as e:
                        Logger.log_error(f"下载进度回调异常: {str(e)}")
                
                # 模拟网络延迟
                time.sleep(0.1)
        
        # 检查是否被停止或超时
        if self._stop_event.is_set():
            Logger.log_info("下载被用户停止")
            if os.path.exists(save_path):
                os.remove(save_path)
            return False
        
        return downloaded_size == total_size
    
    def _verify_downloaded_file(self, file_path):
        """验证下载的文件
        
        Args:
            file_path: 下载的文件路径
            
        Returns:
            bool: 是否验证成功
        """
        # 实际应用中，这里应该验证文件的MD5、SHA1或SHA256哈希值
        # 这里简化处理，只检查文件是否存在且大小合理
        if not os.path.exists(file_path):
            return False
        
        # 检查文件大小
        file_size = os.path.getsize(file_path)
        # 确保文件大小大于0
        if file_size <= 0:
            return False
        
        # 在实际应用中，这里应该从服务器获取预期的哈希值并进行比较
        # 为了简化，这里返回True
        return True
    
    def stop_download(self):
        """停止当前下载任务"""
        Logger.log_info("请求停止下载任务")
        self._stop_event.set()
    
    def get_download_progress(self):
        """获取当前下载进度
        
        Returns:
            int: 下载进度百分比(0-100)
        """
        return self.current_download_progress
    
    def cleanup_downloads(self, keep_latest=False):
        """清理下载文件
        
        Args:
            keep_latest: 是否保留最新的下载文件
        """
        if not os.path.exists(self.download_dir):
            return
        
        try:
            files = [f for f in os.listdir(self.download_dir) if os.path.isfile(os.path.join(self.download_dir, f))]
            
            if keep_latest and files:
                # 按修改时间排序，保留最新的文件
                files.sort(key=lambda x: os.path.getmtime(os.path.join(self.download_dir, x)), reverse=True)
                files_to_delete = files[1:]
            else:
                files_to_delete = files
            
            for file_name in files_to_delete:
                file_path = os.path.join(self.download_dir, file_name)
                os.remove(file_path)
                Logger.log_info(f"已删除旧的下载文件: {file_path}")
        except Exception as e:
            Logger.log_error(f"清理下载文件时发生错误: {str(e)}")

# 示例用法
if __name__ == "__main__":
    def progress_callback(progress, total_size, downloaded_size):
        print(f"下载进度: {progress}% ({downloaded_size/1024/1024:.2f}MB / {total_size/1024/1024:.2f}MB)")
    
    downloader = UpdateDownloader()
    download_url = "https://updates.professionalstockanalysis.com/updates/1.1.0/update_package.zip"
    
    try:
        file_path = downloader.download_update(download_url, progress_callback)
        if file_path:
            print(f"更新包下载成功: {file_path}")
        else:
            print("更新包下载失败")
    except KeyboardInterrupt:
        print("用户中断下载")
        downloader.stop_download()